﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
//using SanctusSoftware.Spelling;

namespace SanctusSoftware.Music.Chords
{

  public class ChordTransposer
  {


    static ChordTransposer()
    {
      //noteTransposer = new NoteTransposer();
    }

    //private static NoteTransposer noteTransposer = null;

    //public const string ChordPattern = "(?<Note>[A-G]([#][#]|bb|[#]|b)?)(?<Chord>[A-Za-z0-9°+()]*)";

    public const string SymbolsUsedInChords = "°+#♯♭";
    public const string ChordPattern = "(?<Note>" + NoteTransposer.NotePattern + ")(?<Chord>[A-Za-z0-9,()" + SymbolsUsedInChords + "]*)";
    public static readonly List<string> ValidChordsValidWords = new List<string>(new string[] { "A", "E", "Ab", "Am", "Em", "Ebb" });
    public static readonly List<string> ValidChordsInvalidWords = new List<string>(new string[] { "Cm" }); // Some valid dictionary words aren't really words that would be used in a song
    public static readonly List<string> ValidWordInvalidChords = new List<string>(new string[] { "Chorus", "Bridge", "Collision" });
    public static readonly List<string> ValidWordInvalidChordPunctuation = new List<string>(new string[] { "'", "‘", "’", "\"", "“", "”" });
    // , "-", "–"

    private static bool ContainsValidWordInvalidChordPunctuation(string word)
    {
      foreach (var item in ValidWordInvalidChordPunctuation)
      {
        if (word.Contains(item))
        {
          return true;
        }
      }
      return false;
    }

    #region Methods (Checking Pattern Match)

    public static bool MatchesChordPattern(string chord)
    {
      return Regex.IsMatch(chord, ChordPattern);
    }

    public static decimal GetChordMatchPercent(string chord)
    {
      return GetChordMatchPercent(chord, null);
    }

    public static decimal GetChordMatchPercent(string chord, bool? isSpelledCorrectly)
    {

      if (!MatchesChordPattern(chord))
      {
        return .00m;
      }

      decimal chordPoints = 0;
      decimal wordPoints = 0;

      if (Regex.IsMatch(chord, "^[BCDFGbcdfg]$"))
      {
        // If it's a single letter and not a vowel, it's a chord    
        // Dumb dictionary considers "B" a word
        chordPoints += 1;
      }
      else if (ValidChordsValidWords.Contains(chord))
      {
        // Might be a chord, Might Not 
        // Give it a 51% chance of being a chord
        chordPoints += 0.51m;
        wordPoints += 0.49m;
      }
      else if (ChordTransposer.ValidChordsInvalidWords.Contains(chord))
      {
        // Some words are valid in the dictionary but realistically, they're NOT song lyrics but instead chords
        chordPoints += 1;
      }
      else if (IsValidWordInvalidChord(chord))
      {
        wordPoints += 1;
      }
      else
      {

        if (UnicodeNormalizationHelper.ContainsDiacritics(chord))
        {
          // If it contains Diacritics, it's probably a WORD
          wordPoints += 1;
        }

        if (ContainsValidWordInvalidChordPunctuation(chord))
        {
          // If it contains Word-specific punctuation, it's probably a WORD
          wordPoints += 1;
        }
        else if (Regex.IsMatch(UnicodeNormalizationHelper.RemoveDiacritics(chord), "[^A-Za-z]"))
        {
          // If it has non-word characters that are NOT word-specific punctuation, it's probably a chord
          chordPoints += 1;
        }


        if (Regex.IsMatch(chord, "[0-9]"))
        {
          // If it contains numbers, it's probably a CHORD
          chordPoints += 1;
        }

        if (Regex.IsMatch(chord, "[" + ChordTransposer.SymbolsUsedInChords + "]"))
        {
          // If it contains symbols used in chords, it's probably a CHORD
          chordPoints += 1;
        }
        else if (!Regex.IsMatch(chord, "[aeiouAEIOU]"))
        {
           // If it contains no vowels it's probably a CHORD (might be a problem for non-english languages
          chordPoints += 1;
        }
        else if (isSpelledCorrectly != null)
        {
          if (isSpelledCorrectly == true)
          {
            wordPoints += 1;
          }
          else
          {
            chordPoints += 1;
          }
        }
        else
        {

          // Custom Dictionary
          //// I think the dictionary is a pig on performance
          //bool isInDictionary = false;
          //try
          //{
          //  isInDictionary = DictionaryManager.IsWordInDictionary(match.Value);
          //}
          //catch (Exception ex)
          //{

          //}

          //if (!isInDictionary)
          //{
          //  // It's not in the dicitonary so it's probably a chord
          //  chordCharacterCount += Convert.ToDecimal(match.Value.Length);
          //  chordWordCount++;
          //}

        }
      }

      if (chordPoints == 0)
      {
        return 0;
      }
      else if (wordPoints == 0)
      {
        return 1;
      }
      else
      {
        return chordPoints / (chordPoints + wordPoints); 
      }

    }

    public static bool IsValidWordInvalidChord(string chord)
    {

      string unwrappedChord = BracketWrapper.Unwrap(chord);

      if (ChordTransposer.ValidWordInvalidChords.Contains(unwrappedChord))
      {
        return true;
      }

      return false;

    }

    #endregion

    #region Methods (Transpose)

    public static string GetTransposedChord(string chord, string originalKey, string transposeTo)
    {
      if (!MatchesChordPattern(chord))
      {
        return chord;
      }
      else
      {
        Match match = Regex.Match(chord, ChordPattern);
        string originalChord = match.Value;
        string noteName = match.Groups["Note"].Value;
        string chordPart = match.Groups["Chord"].Value;

        string targetNoteName = NoteTransposer.GetTransposedNoteName(noteName, originalKey, transposeTo);

        string targetChord = targetNoteName + chordPart;

        return targetChord;
      }
    }

    #endregion



    

    #region Chord Matches


    //public static Match FindChordMatch(string chords)
    //{
    //  return FindChordMatch(chords, 0);
    //}

    public static Match FindChordMatch(string chords, int startIndex)
    {

      MatchCollection matches = Regex.Matches(chords, ChordPattern);

      foreach (Match match in matches)
      {
        if (match.Index >= startIndex)
        {
          return match;
        }
      }

      return null;

    }

    #endregion


  }

}
